package org.googlecode.viewt.core.tools.formbean;

import java.io.File;

import org.googlecode.viewt.core.tools.formbean.types.AttrMappingDef;
import org.googlecode.viewt.core.tools.formbean.types.FormBeanDef;
import org.googlecode.viewt.core.tools.formbean.types.FormBeanToPODef;
import org.googlecode.viewt.core.tools.formbean.types.FormBeanToQueryDef;
import org.googlecode.viewt.core.tools.formbean.types.FormBeans;
import org.googlecode.viewt.core.tools.formbean.types.POToFormBeanDef;
import org.googlecode.viewt.core.tools.formbean.types.Param;
import org.googlecode.viewt.core.tools.formbean.types.PropertyDef;
import org.googlecode.viewt.core.tools.formbean.types.QueryNodes;
import org.googlecode.viewt.core.tools.po.POConfigRepository;
import org.googlecode.viewt.core.tools.po.types.BeanPropertyDef;
import org.googlecode.viewt.core.tools.po.types.PersistObjectDescDef;
import org.googlecode.viewt.core.utils.TypeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FormBeanUtil {
	private static Logger logger = LoggerFactory.getLogger(FormBeanUtil.class);

	public static String getFormBeanModule(String className) {
		if ((className == null) || ("".equals(className))) {
			return null;
		}
		int index = className.lastIndexOf(".formbean.");
		if (index < 0)
			return null;
		String moduleClassName = className.substring(0, index);
		index = moduleClassName.lastIndexOf(46);
		if (index < 0) {
			return null;
		}
		return moduleClassName.substring(index + 1);
	}

	public static String getFormBeanProject(String className) {
		if ((className == null) || ("".equals(className))) {
			return null;
		}
		int index = className.lastIndexOf(".formbean.");
		if (index < 0)
			return null;
		String moduleClassName = className.substring(0, index);
		index = moduleClassName.lastIndexOf(46);
		if (index < 0)
			return null;
		String projectClassName = moduleClassName.substring(0, index);
		index = projectClassName.lastIndexOf(46);
		if (index < 0) {
			return null;
		}
		return projectClassName.substring(index + 1);
	}

	public static String findDepCfgFile(String genCfg, String className) {
		if ((genCfg == null) || ("".equals(genCfg)) || (className == null)
				|| ("".equals(className))) {
			return null;
		}

		String module = getFormBeanModule(className);
		if (module == null) {
			return null;
		}

		File cfgFile = new File(genCfg);
		File path = cfgFile.getParentFile();
		if (path == null)
			return null;
		String schemaPath = path.getName();
		path = path.getParentFile();
		if (path == null)
			return null;
		path = path.getParentFile();
		if (path == null)
			return null;
		String srcPath = path.getAbsolutePath();

		String depCfg = srcPath + File.separator + module + File.separator
				+ schemaPath + File.separator + module + "-formbean.xml";
		path = new File(depCfg);
		if ((path.exists()) && (path.isFile())) {
			return depCfg;
		}
		return null;
	}

	public static boolean validateConfig(
			FormBeanCfgRepository formbeanRepository,
			POConfigRepository poRepository) {
		FormBeans mainDef = formbeanRepository.getMainDef();
		FormBeanDef[] formbeanDefs = mainDef.getFormBeanDef();
		for (int i = 0; i < formbeanDefs.length; ++i) {
			int k;
			if (!(mainDef.getProjectName()
					.equals(getFormBeanProject(formbeanDefs[i].getClassName())))) {
				logger.error("Project name not match, formbean:"
						+ formbeanDefs[i].getClassName());
				return false;
			}
			if (!(mainDef.getModuleName()
					.equals(getFormBeanModule(formbeanDefs[i].getClassName())))) {
				logger.error("Module name not match, formbean:"
						+ formbeanDefs[i].getClassName());
				return false;
			}

			if ((formbeanDefs[i].getParentClass() != null)
					&& (formbeanRepository.getFormBeanConfig(formbeanDefs[i]
							.getParentClass()) == null)) {
				logger.error("Can not find parent class:"
						+ formbeanDefs[i].getParentClass());
				return false;
			}

			PropertyDef[] propDefs = formbeanDefs[i].getPropertyDef();
			for (int j = 0; j < propDefs.length; ++j) {
				String type = propDefs[j].getJavaType();
				propDefs[j].setJavaType(TypeUtil.fullPrimaryClassName(type));
			}

			POToFormBeanDef[] toFormBeanDefs = formbeanDefs[i]
					.getPOToFormBeanDef();
			for (int j = 0; j < toFormBeanDefs.length; ++j) {
				AttrMappingDef[] mappings = toFormBeanDefs[j]
						.getAttrMappingDef();
				for (k = 0; k < mappings.length; ++k) {
					
					if (isAttrProperty(mappings[k].getName(), formbeanDefs[i],
							formbeanRepository))
						continue;
//					System.out.println("mappings[k].getName() " + k + ": "+ isAttrProperty(mappings[k].getName(), formbeanDefs[i],
//							formbeanRepository));
//					System.out.println("mappings[k].getName() " + k + ": "+ mappings[k].getName());
					
					logger.error("PO to formbean mapping attribute:"
							+ mappings[k].getName() + " is not valid");
					return false;
				}

			}

			FormBeanToPODef[] toPODefs = formbeanDefs[i].getFormBeanToPODef();
			for (int j = 0; j < toPODefs.length; ++j) {
				String poClass = toPODefs[j].getPoClass();
				PersistObjectDescDef poConfig = poRepository
						.getPOConfig(poClass);
				if (poConfig == null) {
					logger.error("PO class:" + poClass + " not found");
					return false;
				}

				AttrMappingDef[] mappings = toPODefs[j].getAttrMappingDef();
				for (k = 0; k < mappings.length; ++k) {
					if (isAttrProperty(mappings[k].getName(), poConfig,
							poRepository))
						continue;
					logger.error("FormBean to PO mapping attribute:"
							+ mappings[k].getName() + " is not valid");
					return false;
				}

			}

			FormBeanToQueryDef[] queryDefs = formbeanDefs[i]
					.getFormBeanToQueryDef();
			for (int j = 0; j < queryDefs.length; ++j) {
				QueryNodes[] nodes = queryDefs[j].getQueryNodes();
				for (k = 0; k < nodes.length; ++k) {
					Param[] params = nodes[k].getParam();
					for (int l = 0; l < params.length; ++l) {
						String type = params[l].getJavaType();
						propDefs[j].setJavaType(TypeUtil
								.fullPrimaryClassName(type));
					}
				}
			}
		}

		return true;
	}

	public static boolean isAttrProperty(String attrName,
			FormBeanDef formbeanDef, FormBeanCfgRepository formbeanRepository) {
		return (attrType(attrName, formbeanDef, formbeanRepository) != null);
	}

	public static boolean isAttrProperty(String attrName,
			PersistObjectDescDef poConfig, POConfigRepository poRepository) {
		return (attrType(attrName, poConfig, poRepository) != null);
	}

	public static String attrType(String attrName, FormBeanDef formbeanDef,
			FormBeanCfgRepository formbeanRepository) {
		if ((attrName == null) || (formbeanDef == null)) {
			return null;
		}

		PropertyDef[] propDefs = formbeanDef.getPropertyDef();
		int size = (propDefs == null) ? 0 : propDefs.length;
		for (int i = 0; i < size; ++i) {
			if (attrName.equals(propDefs[i].getName())) {
				return propDefs[i].getJavaType();
			}
		}

		if (formbeanDef.getParentClass() != null) {
			return attrType(attrName, formbeanRepository
					.getFormBeanConfig(formbeanDef.getParentClass()),
					formbeanRepository);
		}

		return null;
	}

	public static String attrType(String attrName, String poClass,
			POConfigRepository poRepository) {
		if ((poRepository == null) || (poClass == null)) {
			return null;
		}
		PersistObjectDescDef poConfig = poRepository.getPOConfig(poClass);
		return attrType(attrName, poConfig, poRepository);
	}

	public static String attrType(String attrName,
			PersistObjectDescDef poConfig, POConfigRepository poRepository) {
		if ((attrName == null) || (poConfig == null)) {
			return null;
		}

//		System.out.println("march: " + 111);
		BeanPropertyDef[] propDefs = poConfig.getBeanPropertyDef();
		int size = (propDefs == null) ? 0 : propDefs.length;
		for (int i = 0; i < size; ++i) {
			if (attrName.equals(propDefs[i].getName())) {
//				System.out.println("march: " + propDefs[i].getName());
				
				return propDefs[i].getType();
			}
		}

		if (poConfig.getParentClassName() != null) {
			return attrType(attrName, poRepository.getPOConfig(poConfig
					.getParentClassName()), poRepository);
		}
		return null;
	}

	public static String poMappingConfigFile(String destPath, String moduleName) {
		if (destPath.endsWith(File.separator)) {
			return destPath + "bean-po" + File.separator + moduleName + ".xml";
		}
		return destPath + File.separator + "bean-po" + File.separator
				+ moduleName + ".xml";
	}

	public static String queryMappingConfigFile(String destPath,
			String moduleName) {
		if (destPath.endsWith(File.separator)) {
			return destPath + "bean-query" + File.separator + moduleName
					+ ".xml";
		}
		return destPath + File.separator + "bean-query" + File.separator
				+ moduleName + ".xml";
	}

	public static String constClass(String prePackName, String projectName,
			String moduleName) {
		return prePackName + "." + projectName + "." + moduleName
				+ ".formbean." + firstUpper(moduleName) + "FormBeanConst";
	}

	public static String firstUpper(String propName) {
		return propName.substring(0, 1).toUpperCase() + propName.substring(1);
	}
}